<template>
  <div class="page" :ref="pageId">
    <div ref="graphContainer" :id="pageId" class="graph-container"></div>
  </div>
</template>

<script lang="ts">
import ResizeObserver from 'resize-observer-polyfill';
import { N_oFlowchart } from '@/types';
import {
  G6,
  T_graphInit,
  graphCfg,
  GraphOptions,
  T_srv,
  Tsrv,
  ts,
  ifs,
  T_modes,
  vue
} from './config';
import './page.scss';

@T_srv.comp
export default class ruleGraphPage extends vue {
  @T_srv.prop({ type: Number, default: 0 }) height: number;

  @T_srv.prop({ type: Number, default: 0 }) width: number;

  @T_srv.prop({ type: Boolean, default: 0 }) autoSize: boolean;

  @T_srv.prop({ type: Object, default: () => {} }) data: Object;

  @T_srv.prop({ type: Boolean, default: 0 }) fitView: boolean;

  @T_srv.prop({ required: false, default: () => {} })
  nodeContextMenuConf: N_oFlowchart.I_contextMenuConf;

  // 父组件compBoxInfo
  @T_srv.prop({
    required: true,
    type: Object,
    default: null
  })
  compBoxInfo: ifs.I_compBoxInfo;

  @T_srv.ref('graphContainer') graphContainer: any;

  private G_compName: string = 'ruleGraphPage';

  private G_graph: any;

  private G_graphCfg: GraphOptions = graphCfg();

  private G_g6Toolbar: any = undefined;

  private G_g6Menu: any = undefined;

  private pageId: string;

  // private nodeAttrs: Array<any> = [];

  private G_compID: string;

  private GT_compBox: ifs.I_compBox;

  private GT_compBoxInfo: ifs.I_compBoxInfo;

  private GT_graphInit: T_graphInit;

  private observer: ResizeObserver = null;

  created() {
    this.GT_compBoxInfo = this.compBoxInfo;
    this.GT_compBox = this.GT_compBoxInfo.TcompBox;
    this.G_compID = this.GT_compBoxInfo.compID;
    this.pageId = `${this.G_compID}-graph-container`;

    // 利用g6的toolbar功能，不使用元素
    this.G_g6Toolbar = new G6.ToolBar({
      getContent: () => {
        return `<span/>`;
      }
    });
    if (!Tsrv.utils.isEmpty(this.nodeContextMenuConf)) {
      const self: any = this;
      // const cfg = {
      //   offsetX: 6,
      //   offsetY: 10,
      //   itemTypes: ['node'],
      //   getContent(e) {
      //     if (
      //       self.G_graph.getCurrentMode() === `default` ||
      //       /^begin$|^end$/.test(e.target.cfg.name)
      //     ) {
      //       return null;
      //     }
      //     const outDiv = document.createElement('div');
      //     outDiv.className = 'xc-page-contextmenu-container';
      //     outDiv.innerHTML = self.nodeContextMenuConf.innerHTML;

      //     return outDiv;
      //   },
      //   handleMenuClick: self.nodeContextMenuConf.handleMenuClick
      // };
      const cfg = {
        offsetX: this.nodeContextMenuConf.offsetX ?? 6,
        offsetY: this.nodeContextMenuConf.offsetY ?? 10,
        itemTypes: this.nodeContextMenuConf.itemType ?? ['node'],
        getContent(e) {
          if (!this.nodeContextMenuConf.handle(e)) {
            return null;
          }
          const outDiv = document.createElement('div');
          outDiv.className = 'xc-page-contextmenu-container';
          outDiv.innerHTML = this.nodeContextMenuConf.innerHTML;

          return outDiv;
        },
        handleMenuClick: this.nodeContextMenuConf.handleMenuClick
      };
      this.G_g6Menu = new G6.Menu(cfg);
    }
  }

  mounted() {
    setTimeout(() => {
      this.init();
      // 画布事件
      this.GT_graphInit.initGraphOn();
      this.autoGraphSize();
    }, 5);
  }

  autoGraphSize() {
    const divElement = this.$refs.graphContainer;
    this.observer = new ResizeObserver(entries => {
      for (const entry of entries) {
        const { width, height } = entry.contentRect;
        this.G_graph.changeSize(
          width > 10 ? width - 10 : width,
          height > 10 ? height - 10 : height
        );
      }
    });
    this.observer.observe(divElement as Element);
  }

  beforeDestroy() {
    this.observer.disconnect(); // 取消DOM元素的监听
    this.observer = null; // 将ResizeObserver实例置为null
  }

  init() {
    const Tmodes = new T_modes(this.G_compID);
    // 加入行为modes
    this.G_graphCfg.modes = Tmodes.modes;
    this.createGraph();
    this.GT_graphInit = new T_graphInit(this.G_graph, this.GT_compBoxInfo);
    this.GT_graphInit.initBehavors(Tmodes);

    // 通知相关插件加入
    this.addPluginEvent();
    this.readData();
    this.GT_compBox.addCompMergeName(this.G_compID, `page`, this);
    this.GT_compBox.addCompMergeName(this.G_compID, 'graph', this.G_graph);
    this.GT_compBox.addCompMergeName(
      this.G_compID,
      'g6Toolbar',
      this.G_g6Toolbar
    );
  }

  getCompBox(): ifs.I_compBox {
    return this.GT_compBox;
  }

  getCompID(): string {
    return this.G_compID;
  }

  getGraph() {
    return this.G_graph;
  }

  createGraph() {
    this.G_graphCfg.height =
      document.getElementById(this.pageId).scrollHeight || 800;
    this.G_graphCfg.width =
      document.getElementById(this.pageId).scrollWidth || 1000;

    this.G_graphCfg.fitView = this.fitView;
    this.G_graphCfg.container = this.pageId;

    this.G_graph = new G6.Graph(this.G_graphCfg);
  }

  addPluginEvent() {
    this.$bus.$emit(`${this.G_compID}_graphCreated}`, this.G_graph);
    this.G_g6Toolbar && this.G_graph.addPlugin(this.G_g6Toolbar);
    this.G_g6Menu && this.G_graph.addPlugin(this.G_g6Menu);
  }

  readData() {
    this.data && this.G_graph.read(this.data);
    this.G_graph.fitView();
  }

  destroyed() {
    this.GT_graphInit = null;
    this.G_graph.destroy();

    this.GT_compBox.removeCompsMergeName(this.G_compID, [
      'page',
      'graph',
      'g6Toolbar'
    ]);
  }

  // nodeAttrs -> page.nodeAttrs
  onNodeMouseOut(e) {
    if (e.item.getModel().shape === 'hLaneNode') {
      // 泳道图在下一层
      e.item.toBack();
      this.GT_compBox.getCompMergeName(this.G_compID, `graph`).paint();
    }
  }

  removeNodeattr(nodeId) {
    const nodeAttrs = this.$data.nodeAttrs;
    let removeRec = [];
    removeRec = nodeAttrs.filter(item => item.nodeId !== nodeId);
    nodeAttrs.splice(0, nodeAttrs.length);
    if (removeRec.length > 0) {
      removeRec.forEach(item => {
        nodeAttrs.push({ ...item });
      });
    }
  }

  saveNodeAttrData(attrs) {
    // page.form
    const nodeAttrs = this.$data.nodeAttrs;
    let isUpdate = false;
    // eslint-disable-next-line array-callback-return
    nodeAttrs.map((item, index) => {
      if (item.nodeId === attrs.nodeId) {
        isUpdate = true;
        nodeAttrs.splice(index, 1, { ...attrs });
      }
    });
    if (!isUpdate) {
      nodeAttrs.push({ ...attrs });
    }
  }
}
</script>

<style scoped lang="scss">
.graph-container,
.page {
  position: relative;
  height: 100%;
  width: 100%;
  padding: 0;
  margin: 0;
  z-index: 1;
}
</style>
